#include "camera_utils.h"

// 写入数据回调函数
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
    return fwrite(ptr, size, nmemb, stream);
}

// 写入数据到内存回调函数
size_t write_data_to_memory(void *contents, size_t size, size_t nmemb, void *userp) {
    size_t realsize = size * nmemb;
    struct MemoryStruct *mem = (struct MemoryStruct *)userp;
    
    char *ptr = realloc(mem->memory, mem->size + realsize + 1);
    if(!ptr) {
        fprintf(stderr, "内存分配失败\n");
        return 0;
    }
    
    mem->memory = ptr;
    memcpy(&(mem->memory[mem->size]), contents, realsize);
    mem->size += realsize;
    mem->memory[mem->size] = 0;
    
    return realsize;
}

// 检查数据是否是有效的JPEG
int is_valid_jpeg(unsigned char *data, size_t size) {
    // 避免未使用参数的警告
    (void)data;
    
    // 对于非常小的数据包，可能不是图像
    if (size < 100) return 0;
    
    // JPEG文件应以0xFF 0xD8开始，但我们不过于严格验证，因为摄像头数据可能会有变化
    // 对于400W和800W摄像头，只要数据大小合理就认为是有效的
    return 1;
}

// 获取当前时间的格式化字符串
void get_time_string(char *buffer, size_t size) {
    time_t now = time(NULL);
    struct tm *t = localtime(&now);
    strftime(buffer, size, "%Y%m%d_%H%M%S", t);
}

// 创建目录（如果不存在）
int create_directory(const char *path) {
    struct stat st = {0};
    
    // 检查目录是否存在
    if (stat(path, &st) == -1) {
        // 在Linux/Unix上创建目录
        #ifdef __linux__
            return mkdir(path, 0777);  // 将目录权限修改为777
        // 在Windows上创建目录
        #elif _WIN32
            return mkdir(path);
        #else
            return -1;
        #endif
    }
    
    return 0; // 目录已存在
}

// 尝试从400W摄像头获取图像 - 使用确认有效的URL
int try_camera_400w_urls(const CameraConfig *config, const char *time_str, const char *filepath) {
    // 避免未使用参数的警告
    (void)time_str;
    
    char url[256];
    // 使用已验证可用的URL
    snprintf(url, sizeof(url), "http://%s/ISAPI/Streaming/channels/102/picture", config->ip);
    
    // 直接尝试获取图像
    return try_single_url_with_validation(config, url, filepath);
}

// 尝试单个URL，添加数据验证
int try_single_url_with_validation(const CameraConfig *config, const char *url, const char *filepath) {
    CURL *curl;
    CURLcode res;
    int ret = -1;
    
    // 使用内存缓冲区接收数据
    struct MemoryStruct chunk;
    
    chunk.memory = malloc(1);  // 为了realloc
    chunk.size = 0;    // 当前没有数据
    
    // 初始化libcurl
    curl = curl_easy_init();
    if (curl) {
        // 设置URL
        curl_easy_setopt(curl, CURLOPT_URL, url);
        
        // 设置用户名和密码，使用摘要认证
        curl_easy_setopt(curl, CURLOPT_USERNAME, config->username);
        curl_easy_setopt(curl, CURLOPT_PASSWORD, config->password);
        curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
        
        // 设置写入数据回调到内存
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data_to_memory);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
        
        // 设置超时
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L);
        
        // 执行请求
        res = curl_easy_perform(curl);
        
        // 检查请求是否成功
        if(res != CURLE_OK) {
            ret = -1;
        } else {
            // 验证获取到的数据是否是有效的JPEG
            if (chunk.size > 0 && is_valid_jpeg((unsigned char*)chunk.memory, chunk.size)) {
                // 写入文件
                FILE *fp = fopen(filepath, "wb");
                if (fp) {
                    if (fwrite(chunk.memory, 1, chunk.size, fp) == chunk.size) {
                        // 成功保存图像
                        printf("成功保存: %s\n", filepath);
                        
                        // 设置文件权限为777
                        #ifdef __linux__
                            if (chmod(filepath, 0777) != 0) {
                                fprintf(stderr, "无法修改文件权限: %s\n", filepath);
                            }
                        #endif
                        ret = 0;
                    }
                    fclose(fp);
                }
            }
        }
        
        // 清理curl
        curl_easy_cleanup(curl);
    }
    
    // 释放内存
    free(chunk.memory);
    
    return ret;
}

// 尝试带认证信息的URL (不使用摘要认证)，添加数据验证
int try_auth_url_with_validation(const CameraConfig *config, const char *url, const char *filepath) {
    CURL *curl;
    CURLcode res;
    int ret = -1;
    
    // 避免未使用参数的警告
    (void)config;
    
    // 使用内存缓冲区接收数据
    struct MemoryStruct chunk;
    
    chunk.memory = malloc(1);  // 为了realloc
    chunk.size = 0;    // 当前没有数据
    
    // 初始化libcurl
    curl = curl_easy_init();
    if (curl) {
        // 设置URL
        curl_easy_setopt(curl, CURLOPT_URL, url);
        
        // 不使用摘要认证，认证信息已包含在URL中
        
        // 设置写入数据回调到内存
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data_to_memory);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
        
        // 设置超时
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L);
        
        // 执行请求
        res = curl_easy_perform(curl);
        
        // 检查请求是否成功
        if(res != CURLE_OK) {
            ret = -1;
        } else {
            // 验证获取到的数据是否是有效的JPEG
            if (chunk.size > 0 && is_valid_jpeg((unsigned char*)chunk.memory, chunk.size)) {
                // 写入文件
                FILE *fp = fopen(filepath, "wb");
                if (fp) {
                    if (fwrite(chunk.memory, 1, chunk.size, fp) == chunk.size) {
                        printf("成功保存: %s\n", filepath);
                        
                        // 设置文件权限为777
                        #ifdef __linux__
                            if (chmod(filepath, 0777) != 0) {
                                fprintf(stderr, "无法修改文件权限: %s\n", filepath);
                            }
                        #endif
                        ret = 0;
                    }
                    fclose(fp);
                }
            }
        }
        
        // 清理curl
        curl_easy_cleanup(curl);
    }
    
    // 释放内存
    free(chunk.memory);
    
    return ret;
}

// 从摄像头捕获图像
int capture_image(const CameraConfig *config) {
    char filepath[512];
    char time_str[32];
    int ret = 0;
    
    // 获取当前时间字符串
    get_time_string(time_str, sizeof(time_str));
    
    // 构建保存文件的完整路径
    snprintf(filepath, sizeof(filepath), "%s/%s_%s.jpg", 
             config->save_dir, config->prefix, time_str);
    
    // 确保目录存在
    create_directory(config->save_dir);
    
    // 根据摄像头IP选择不同的处理逻辑
    if (strcmp(config->ip, "192.168.1.60") == 0) {
        // 对于400W摄像头 (DS-2CD3T46WDV3-I3)，使用特定URL
        ret = try_camera_400w_urls(config, time_str, filepath);
    } else {
        // 对于800W摄像头 (DS-2CD3T86FWDV3-I3s)，使用标准URL
        char url[256];
        snprintf(url, sizeof(url), "http://%s/ISAPI/Streaming/channels/1/picture", config->ip);
        ret = try_single_url_with_validation(config, url, filepath);
    }
    
    return ret;
}

// 摄像头线程函数
void *camera_thread(void *arg) {
    CameraConfig *config = (CameraConfig *)arg;
    
    while (1) {
        // 捕获图像
        if (capture_image(config) != 0) {
            fprintf(stderr, "从摄像头 %s 捕获图像失败\n", config->ip);
        }
        
        // 休眠10秒
        sleep(10);
    }
    
    return NULL;
}

// 设置摄像头时间与系统时间同步
int set_camera_time(const CameraConfig *config) {
    CURL *curl;
    CURLcode res;
    int ret = -1;
    struct curl_slist *headers = NULL;
    
    // 使用内存缓冲区接收响应数据
    struct MemoryStruct response;
    response.memory = malloc(1);  // 为了realloc
    response.size = 0;    // 当前没有数据
    
    // 获取当前系统时间
    time_t now = time(NULL);
    struct tm *t = localtime(&now);
    
    // 构建XML格式的时间设置数据
    char xml_data[512];
    snprintf(xml_data, sizeof(xml_data), 
             "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
             "<Time>\n"
             "  <timeMode>manual</timeMode>\n"
             "  <localTime>%04d-%02d-%02dT%02d:%02d:%02d</localTime>\n"
             "  <timeZone>CST-8:00:00</timeZone>\n"
             "</Time>",
             t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
             t->tm_hour, t->tm_min, t->tm_sec);
    
    // 初始化libcurl
    curl = curl_easy_init();
    if (curl) {
        // 构建URL
        char url[256];
        snprintf(url, sizeof(url), "http://%s/ISAPI/System/time", config->ip);
        
        // 设置URL
        curl_easy_setopt(curl, CURLOPT_URL, url);
        
        // 设置用户名和密码，使用摘要认证
        curl_easy_setopt(curl, CURLOPT_USERNAME, config->username);
        curl_easy_setopt(curl, CURLOPT_PASSWORD, config->password);
        curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
        
        // 设置为PUT请求
        curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
        
        // 添加内容类型头
        headers = curl_slist_append(headers, "Content-Type: application/xml");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        
        // 设置要发送的数据
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, xml_data);
        
        // 设置回调函数接收响应数据但不打印
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data_to_memory);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response);
        
        // 设置超时
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L);
        
        // 执行请求
        res = curl_easy_perform(curl);
        
        // 检查请求是否成功
        if(res == CURLE_OK) {
            long response_code;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
            
            if (response_code == 200) {
                printf("成功设置摄像头 %s 的时间\n", config->ip);
                ret = 0;
            } else {
                fprintf(stderr, "设置摄像头 %s 时间失败，HTTP代码: %ld\n", config->ip, response_code);
            }
        } else {
            fprintf(stderr, "设置摄像头 %s 时间失败: %s\n", config->ip, curl_easy_strerror(res));
        }
        
        // 释放header列表
        curl_slist_free_all(headers);
        
        // 清理curl
        curl_easy_cleanup(curl);
    }
    
    // 释放响应内存
    free(response.memory);
    
    return ret;
} 